/*
 *  Copyright © OpenAtom Foundation.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.openatom.ubml.model.be.definition;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.util.ArrayList;
import java.util.function.Predicate;
import org.openatom.ubml.model.be.definition.beenum.BECategory;
import org.openatom.ubml.model.be.definition.beenum.BETriggerTimePointType;
import org.openatom.ubml.model.be.definition.beenum.GspDataLockType;
import org.openatom.ubml.model.be.definition.json.model.BizEntityDeserializer;
import org.openatom.ubml.model.be.definition.json.model.BizEntitySerializer;
import org.openatom.ubml.model.be.definition.operation.Determination;
import org.openatom.ubml.model.be.definition.operation.collection.BizMgrActionCollection;
import org.openatom.ubml.model.be.definition.operation.internalmgraction.DeleteMgrAction;
import org.openatom.ubml.model.be.definition.operation.internalmgraction.ModifyMgrAction;
import org.openatom.ubml.model.be.definition.operation.internalmgraction.QueryMgrAction;
import org.openatom.ubml.model.be.definition.operation.internalmgraction.RetrieveDefaultMgrAction;
import org.openatom.ubml.model.be.definition.operation.internalmgraction.RetrieveMgrAction;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonModel;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonObject;
import org.openatom.ubml.model.common.definition.commonmodel.entity.GspCommonModel;
import org.openatom.ubml.model.common.definition.entity.IMetadataContent;

/**
 * The Definition Of Business Entity Metadata
 *
 * @ClassName: GspBusinessEntity
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
@JsonSerialize(using = BizEntitySerializer.class)
@JsonDeserialize(using = BizEntityDeserializer.class)
public class GspBusinessEntity extends GspCommonModel implements IMetadataContent {
    // region 属性

    boolean isUsingTimeStamp;
    boolean enableCaching = false;
    boolean enableTreeDtm = true;
    /**
     * 生成构件程序集名
     */
    private String privateComponentAssemblyName;
    /**
     * BE 实体类型
     */
    private BECategory privateCategory = BECategory.forValue(0);
    /**
     * 实体数据加锁类型 此属性影响到实体使用乐观锁或者悲观锁控制数据并发 默认为悲观锁，保证更好的数据一致性，同时可以提升用户体验。必须显式加锁才能编辑数据
     */
    private GspDataLockType privateDataLockType = GspDataLockType.forValue(0);
    private String dependentEntityId;
    private String dependentEntityName;
    private String dependentEntityPackageName;
    private String cacheConfiguration = "";
    private BizMgrActionCollection beMgrActions;

    // region Ctor
    public GspBusinessEntity() {
        getBizMgrActions().add(new QueryMgrAction());
        getBizMgrActions().add(new RetrieveDefaultMgrAction());
        getBizMgrActions().add(new RetrieveMgrAction());
        getBizMgrActions().add(new ModifyMgrAction());
        getBizMgrActions().add(new DeleteMgrAction());
    }

    public final String getComponentAssemblyName() {
        return privateComponentAssemblyName;
    }

    public final void setComponentAssemblyName(String value) {
        privateComponentAssemblyName = value;
    }

    public BECategory getCategory() {
        return privateCategory;
    }

    public void setCategory(BECategory value) {
        privateCategory = value;
    }

    /**
     * BE根节点
     */
    public final GspBizEntityObject getMainObject() {
        return (GspBizEntityObject)super.getMainObject();
    }

    public final void setMainObject(GspBizEntityObject value) {

        super.setCmMainObject(value);
    }

    public final GspDataLockType getDataLockType() {
        return privateDataLockType;
    }

    public final void setDataLockType(GspDataLockType value) {
        privateDataLockType = value;
    }

    /**
     * 扩展类型，固定返回BE类型，用于兼容
     */
    @Override
    public String getExtendType() {
        return "GspBusinessEntity";
    }

    /**
     * 被依赖实体的id
     */
    public String getDependentEntityId() {
        return dependentEntityId;
    }

    public void setDependentEntityId(String value) {
        dependentEntityId = value;
    }

    /**
     * 被依赖实体的名称
     */
    public String getDependentEntityName() {
        return dependentEntityName;
    }

    public void setDependentEntityName(String value) {
        dependentEntityName = value;
    }

    /**
     * 被依赖的实体包名
     */
    public String getDependentEntityPackageName() {
        return dependentEntityPackageName;
    }

    public void setDependentEntityPackageName(String value) {
        dependentEntityPackageName = value;
    }

    public final BizMgrActionCollection getBizMgrActions() {
        if (beMgrActions == null) {
            beMgrActions = new BizMgrActionCollection();
        }
        beMgrActions.setOwner(this.getMainObject());
        return beMgrActions;
    }

    // private java.util.ArrayList<AuthorizationInfo> authorizations;

    /**
     * BE关联的权限对象ID集合
     *
     */
    // java.util.ArrayList<AuthorizationInfo> getAuthorizations()

    // public void setAuthorizations(java.util.ArrayList<AuthorizationInfo> value)

    public final void setBizMgrActions(BizMgrActionCollection value) {
        beMgrActions = value;
        beMgrActions.setOwner(this.getMainObject());
    }

    /**
     * 是否生成时间戳字段（仅主表）
     */
    public boolean getIsUsingTimeStamp() {
        return isUsingTimeStamp;
    }

    public void setIsUsingTimeStamp(boolean value) {
        isUsingTimeStamp = value;
    }

    /**
     * 缓存配置
     */
    public String getCacheConfiguration() {
        return cacheConfiguration;
    }

    public void setCacheConfiguration(String value) {
        cacheConfiguration = value;
    }

    /**
     * 是否启用缓存
     */
    public boolean getEnableCaching() {
        return enableCaching;
    }

    public void setEnableCaching(boolean value) {
        enableCaching = value;
    }

    /**
     * 是否启用树内置动作
     */
    public boolean getEnableTreeDtm() {
        return enableTreeDtm;
    }

    // endregion

    public void setEnableTreeDtm(boolean value) {
        enableTreeDtm = value;
    }

    public final ArrayList<String> getAllDbos() {
        ArrayList<String> list = new ArrayList<>();
        for (GspBizEntityObject object : getAllNodes()) {
            list.add(object.getRefObjectName());
        }
        return list;
    }

    public final java.util.ArrayList<GspBizEntityObject> getAllNodes() {
        throw new UnsupportedOperationException();
    }

    /**
     * 查询符合条件的Node集合
     *
     * @param predicate 查询条件
     * @return 返回结果按照层次遍历顺序
     */
    public final ArrayList<GspBizEntityObject> getAllNodes(Predicate<GspBizEntityObject> predicate) {

        ArrayList<GspBizEntityObject> bizObjs = getAllNodes();
        ArrayList<GspBizEntityObject> result = new ArrayList<GspBizEntityObject>();
        for (GspBizEntityObject item : bizObjs) {
            if (predicate.test(item)) {
                result.add(item);
            }
        }
        return result;
    }

    /**
     * 查询符合条件的第一个节点
     *
     * @param predicate
     * @return
     */
    public final GspBizEntityObject getNode(Predicate<GspBizEntityObject> predicate) {
        ArrayList<GspBizEntityObject> result = getAllNodes(predicate);
        if (result.size() > 0) {
            return result.get(0);
        }
        return null;
    }

    /**
     * 查询指定Code的节点
     *
     * @param nodeCode
     * @return
     */
    public final GspBizEntityObject getNode(String nodeCode) {
        return getNode(pre -> pre.getCode().equals(nodeCode));
    }

    public final IGspCommonModel copyToCommonModel() {
        // TODO 后续换成Copy方法
        return this;
    }

    /**
     * 获取某一时机所有的Dtm，并按先子后主排序
     *
     * @param timePoint 执行时机
     * @return 如果找不到返回空集合
     */
    public final java.util.ArrayList<Determination> getAllDtmWithTriggerTime(BETriggerTimePointType timePoint) {
        java.util.ArrayList<Determination> dtms = new java.util.ArrayList<Determination>();
        java.util.Stack<GspBizEntityObject> bizObjecs = new java.util.Stack<GspBizEntityObject>();
        getBizObjectFromChildToParent(new java.util.ArrayList<GspBizEntityObject>(
                java.util.Arrays.asList(new GspBizEntityObject[]{getMainObject()})), bizObjecs);
        while (bizObjecs.size() > 0) {
            ArrayList<Determination> list = bizObjecs.pop().getDeterminations()
                    .getFiltedDtms(dtm -> dtm.getTriggerTimePointType().contains(timePoint));
            dtms.addAll(list);
        }
        return dtms;
    }

    /**
     * 获取所有的节点，按先子后主的顺序
     *
     * @param childObjects
     * @param bizObjects
     */
    private void getBizObjectFromChildToParent(java.util.ArrayList<GspBizEntityObject> childObjects,
                                               java.util.Stack<GspBizEntityObject> bizObjects) {
        if (childObjects.size() > 0) {
            java.util.ArrayList<GspBizEntityObject> childs = new java.util.ArrayList<GspBizEntityObject>();
            for (IGspCommonObject obj : childObjects) {
                GspBizEntityObject item = (GspBizEntityObject)obj;
                bizObjects.push(item);

                for (IGspCommonObject childObj : item.getContainChildObjects()) {
                    childs.add((GspBizEntityObject)childObj);
                }
            }
            getBizObjectFromChildToParent(childs, bizObjects);
        }
    }

    /**
     * 合并自模板实体
     *
     * @param dependentEntity 模板实体
     */
    public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity) {
        mergeWithDependentEntity(dependentEntity, false);
    }

    public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity, boolean isInit) {
        if (dependentEntity.getCategory() != BECategory.DependentBusinessEntity) {
            throw new RuntimeException("Exception");
        }
        // 初始化dbe带出主对象
        getMainObject().setIsRef(true);

        getMainObject().mergeWithDependentObject(dependentEntity.getMainObject(), isInit);
        mergeMgrActions(dependentEntity);
    }

    private void mergeMgrActions(GspBusinessEntity dependentEntity) {
        getBizMgrActions().mergeDbeOperations(dependentEntity.getBizMgrActions());
    }

    /**
     * 克隆
     *
     * @return
     */
    // C# TO JAVA CONVERTER WARNING: There is no Java equivalent to C#'s shadowing
    // via the 'new' keyword:
    // ORIGINAL LINE: public new object clone()
    public GspBusinessEntity clone() {
        GspBusinessEntity be = (GspBusinessEntity)super.clone();
        if (be == null) {
            return null;
        }
        if (getBizMgrActions() != null) {
            Object tempVar = getBizMgrActions().clone();
            be.setBizMgrActions((BizMgrActionCollection)((tempVar instanceof BizMgrActionCollection) ? tempVar : null));
        }
        return be;
    }
}